/*
 * Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.xuexiang.xui_lib.util;

import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorGroup;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.colors.RgbColor;
import ohos.agp.components.AbsButton;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.ComponentParent;
import ohos.agp.components.Image;
import ohos.agp.components.ListContainer;
import ohos.agp.components.Text;
import ohos.agp.components.TextField;
import ohos.agp.components.element.Element;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.text.Font;
import ohos.agp.utils.Color;
import ohos.agp.utils.Matrix;
import ohos.agp.utils.Rect;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;
import ohos.app.Environment;
import ohos.global.resource.NotExistException;
import ohos.global.resource.RawFileEntry;
import ohos.global.resource.Resource;
import ohos.global.resource.ResourceManager;
import ohos.global.resource.WrongTypeException;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;

import com.xuexiang.xui_lib.component.imageview.ImageLoader;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

/**
 * UI控件工具类
 *
 * @author xuexiang
 * @since 2019-01-03
 */
public final class ViewUtils {
    private static final HiLogLabel LOG_LABEL = new HiLogLabel(HiLog.LOG_APP, 0x00202, "ViewUtils");

    private ViewUtils() {
        throw new UnsupportedOperationException("u can't instantiate me...");
    }

    // copy from View.generateViewId for API <= 16
//    private static final AtomicInteger ATOMIC_INTEGER = new AtomicInteger(1);

    public static void setBackground(Component component, Element element) {
        component.setBackground(element);
    }

    public static void setBackgroundKeepingPadding(Component component, Element element) {
        int[] padding = new int[]{
            component.getPaddingLeft(),
            component.getPaddingTop(),
            component.getPaddingRight(),
            component.getPaddingBottom()
        };
        setBackground(component, element);
        component.setPadding(padding[0], padding[1], padding[2], padding[3]);
    }

    public static void setBackgroundKeepingPadding(Component component, int backgroundResId) {
//        try {
//            setBackgroundKeepingPadding(component,
//                new PixelMapElement(component.getContext().getResourceManager().getResource(backgroundResId)));
//        } catch (IOException | NotExistException e) {
//            e.printStackTrace();
//        }
    }

    public static void setBackgroundColorKeepPadding(Component component, int color) {
        int[] padding = new int[]{
            component.getPaddingLeft(),
            component.getPaddingTop(),
            component.getPaddingRight(),
            component.getPaddingBottom()
        };
        component.setBackground(ColorUtils.getColorShapeElement(color));
        component.setPadding(padding[0], padding[1], padding[2], padding[3]);
    }

    /**
     * 对 Component 的做背景闪动的动画
     *
     * @param v v
     * @param bgColor bgColor
     */
    public static void playBackgroundBlinkAnimation(final Component v, int bgColor) {
        if (v == null) {
            return;
        }
        int[] alphaArray = new int[]{255, 0};
        playViewBackgroundAnimation(v, bgColor, alphaArray, 500);
    }

    /**
     * 对 Component 做背景色变化的动作
     *
     * @param component 做背景色变化的View
     * @param bgColor 背景色
     * @param alphaArray 背景色变化的alpha数组，如 int[]{255,0} 表示从纯色变化到透明
     * @param stepDuration 每一步变化的时长
     * @param endAction 动画结束后的回调
     * @return return
     */
    public static Animator playViewBackgroundAnimation(final Component component, int bgColor, int[] alphaArray,
                                                       int stepDuration, final Runnable endAction) {
//        int animationCount = alphaArray.length - 1;
        ShapeElement bgDrawable = new ShapeElement();
        bgDrawable.setRgbColor(RgbColor.fromArgbInt(bgColor));
        final Element oldBgDrawable = component.getBackgroundElement();
        setBackgroundKeepingPadding(component, bgDrawable);

        OfAnimatorValue valueAnimator = new OfAnimatorValue().ofValue(alphaArray[0], alphaArray[1]).duration(stepDuration);
        valueAnimator.setValueUpdateListener((animatorValue, value) -> {
            int color = ColorUtils.setColorAlpha(bgColor, value / 255F);
            component.setBackground(ColorUtils.getColorShapeElement(color));
        });
        AnimatorGroup animatorSet = new AnimatorGroup();
        animatorSet.setDuration(stepDuration);
        animatorSet.setStateChangedListener(new StateChangedListenerAdapter() {
            @Override
            public void onStop(Animator animator) {
                setBackgroundKeepingPadding(component, oldBgDrawable);
                if (endAction != null) {
                    endAction.run();
                }
            }
        });
        valueAnimator.setStateChangedListener(new StateChangedListenerAdapter() {
            @Override
            public void onEnd(Animator animator) {
                animatorSet.start();
            }
        });
        valueAnimator.start();
        return valueAnimator;
    }

    public static void playViewBackgroundAnimation(final Component v, int bgColor, int[] alphaArray, int stepDuration) {
        playViewBackgroundAnimation(v, bgColor, alphaArray, stepDuration, null);
    }

    /**
     * 对 Component 做背景色变化的动作
     *
     * @param component 做背景色变化的View
     * @param startColor 动画开始时 Component 的背景色
     * @param endColor 动画结束时 Component 的背景色
     * @param duration 动画总时长
     * @param repeatCount 动画重复次数
     * @param setAnimTagId 将动画设置tag给view,若为0则不设置
     * @param endAction 动画结束后的回调
     */
    public static void playViewBackgroundAnimation(final Component component, int startColor, int endColor, long duration,
                                                   int repeatCount, int setAnimTagId, final Runnable endAction) {
        final Element oldBgDrawable = component.getBackgroundElement(); // 存储旧的背景
        ViewUtils.setBackgroundColorKeepPadding(component, startColor);

        OfAnimatorValue anim = new OfAnimatorValue().ofValue(startColor, endColor);


        anim.setDuration(duration / (repeatCount + 1));
        anim.setLoopedCount(repeatCount);
        anim.setRepeatMode(OfAnimatorValue.LOOP_MODE_REVERSE);

        anim.setValueUpdateListener((animatorValue, value) -> ViewUtils.setBackgroundColorKeepPadding(component, (int) value));

        if (setAnimTagId != 0) {
            component.setTag(anim);
        }
        anim.setStateChangedListener(new StateChangedListenerAdapter() {
            @Override
            public void onEnd(Animator animator) {
                setBackgroundKeepingPadding(component, oldBgDrawable);
                if (endAction != null) {
                    endAction.run();
                }
            }
        });
        anim.start();
    }

    public static void playViewBackgroundAnimation(final Component v, int startColor, int endColor, long duration) {
        playViewBackgroundAnimation(v, startColor, endColor, duration, 0, 0, null);
    }

    /**
     * <p>对 Component 做透明度变化的进场动画。</p>
     * <p>相关方法 {@link #fadeOut(Component, int, Animator.StateChangedListener, Animator.LoopedListener, boolean)}</p>
     *
     * @param component 做动画的 View
     * @param duration 动画时长(毫秒)
     * @param listener 动画回调
     * @return return
     */
    public static Animator fadeIn(Component component, int duration, Animator.StateChangedListener listener) {
        return fadeIn(component, duration, listener, true);
    }

    /**
     * <p>对 Component 做透明度变化的进场动画。</p>
     * <p>相关方法 {@link #fadeOut(Component, int, Animator.StateChangedListener, Animator.LoopedListener, boolean)}</p>
     *
     * @param component 做动画的 View
     * @param duration 动画时长(毫秒)
     * @param listener 动画回调
     * @param isNeedAnimation 是否需要动画
     * @return return
     */
    public static Animator fadeIn(Component component, int duration, Animator.StateChangedListener listener,
                                  boolean isNeedAnimation) {
        if (component == null) {
            return null;
        }
        if (isNeedAnimation) {
            component.setVisibility(Component.VISIBLE);
            AnimatorProperty alpha = new AnimatorProperty();
            alpha.alphaFrom(0).alpha(1);
            alpha.setCurveType(Animator.CurveType.DECELERATE);
            alpha.setDuration(duration);
            //alpha.setFillAfter(true);
            if (listener != null) {
                alpha.setStateChangedListener(listener);
            }
            alpha.setTarget(component);
            alpha.start();
            return alpha;
        } else {
            component.setAlpha(1);
            component.setVisibility(Component.VISIBLE);
            return null;
        }
    }

    /**
     * <p>对 Component 做透明度变化的退场动画</p>
     * <p>相关方法 {@link #fadeIn(Component, int, Animator.StateChangedListener, boolean)}</p>
     *
     * @param component 做动画的 View
     * @param duration 动画时长(毫秒)
     * @param listener 动画回调
     * @return return
     */
    public static Animator fadeOut(Component component, int duration, Animator.StateChangedListener listener) {
        return fadeOut(component, duration, listener, null);
    }

    /**
     * <p>对 Component 做透明度变化的退场动画</p>
     * <p>相关方法 {@link #fadeIn(Component, int, Animator.StateChangedListener, boolean)}</p>
     *
     * @param component 做动画的 View
     * @param duration 动画时长(毫秒)
     * @param listener 动画回调
     * @param loopedListener 循环回调
     * @return return
     */
    public static Animator fadeOut(Component component, int duration, Animator.StateChangedListener listener,
                                   Animator.LoopedListener loopedListener) {
        return fadeOut(component, duration, listener, loopedListener, true);
    }

    /**
     * <p>对 Component 做透明度变化的退场动画</p>
     * <p>相关方法 {@link #fadeIn(Component, int, Animator.StateChangedListener, boolean)}</p>
     *
     * @param component 做动画的 View
     * @param duration 动画时长(毫秒)
     * @param listener 动画回调
     * @param loopedListener 循环回调
     * @param isNeedAnimation 是否需要动画
     * @return return
     */
    public static Animator fadeOut(Component component, int duration, Animator.StateChangedListener listener,
                                   Animator.LoopedListener loopedListener, boolean isNeedAnimation) {
        if (component == null) {
            return null;
        }
        if (isNeedAnimation) {
            AnimatorProperty alpha = new AnimatorProperty();
            alpha.alphaFrom(1).alpha(0);
            alpha.setCurveType(Animator.CurveType.DECELERATE);
            alpha.setDuration(duration);
            alpha.setStateChangedListener(new StateChangedListenerAdapter() {
                @Override
                public void onStart(Animator animator) {
                    component.setVisibility(Component.VISIBLE);
                    if (listener != null) {
                        listener.onStart(animator);
                    }
                }

                @Override
                public void onEnd(Animator animator) {
                    component.setVisibility(Component.HIDE);
                    if (listener != null) {
                        listener.onEnd(animator);
                    }
                }
            });
            alpha.setLoopedListener(animator -> {
                if (loopedListener != null) {
                    loopedListener.onRepeat(animator);
                }
            });
            alpha.setTarget(component);
            alpha.start();
            return alpha;
        } else {
            component.setVisibility(Component.HIDE);
            return null;
        }
    }

    /**
     * 清除数值动画
     *
     * @param animator
     */
    public static void clearValueAnimator(Animator animator) {
        if (animator != null) {
            animator.cancel();
        }
    }

    /**
     * 计算控件在屏幕上的坐标
     *
     * @param component component
     * @return return
     */
    public static Rect calculateViewScreenLocation(Component component) {
        // 获取控件在屏幕中的位置，返回的数组分别为控件左顶点的 x、y 的值
        int[] location = component.getLocationOnScreen();
        return new Rect(location[0], location[1], location[0] + component.getWidth(),
            location[1] + component.getHeight());
    }

    /**
     * <p>对 Component 做上下位移的进场动画</p>
     * <p>相关方法 {@link #slide(Component, int, Animator.StateChangedListener, boolean, boolean, Direction)}</p>
     *
     * @param component 做动画的 View
     * @param duration 动画时长(毫秒)
     * @param listener 动画回调
     * @param direction 进场动画的方向
     * @return 动画对应的 Animator 对象, 注意无动画时返回 null
     */
    public static Animator slideIn(Component component, int duration, Animator.StateChangedListener listener,
                                   Direction direction) {
        return slideIn(component, duration, listener, true, direction);
    }

    /**
     * <p>对 Component 做上下位移的进场动画</p>
     * <p>相关方法 {@link #slide(Component, int, Animator.StateChangedListener, boolean, boolean, Direction)}</p>
     *
     * @param component 做动画的 View
     * @param duration 动画时长(毫秒)
     * @param listener 动画回调
     * @param isNeedAnimation 是否需要动画
     * @param direction 进场动画的方向
     * @return 动画对应的 Animator 对象, 注意无动画时返回 null
     */
    public static Animator slideIn(Component component, int duration, Animator.StateChangedListener listener,
                                   boolean isNeedAnimation, Direction direction) {
        return slide(component, duration, listener, isNeedAnimation, false, direction);
    }

    /**
     * <p>对 Component 做上下位移的退场动画</p>
     * <p>相关方法 {@link #slideIn(Component, int, Animator.StateChangedListener, boolean, Direction)}</p>
     *
     * @param component 做动画的 View
     * @param duration 动画时长(毫秒)
     * @param listener 动画回调
     * @param direction 进场动画的方向
     * @return 动画对应的 Animator 对象, 注意无动画时返回 null
     */
    public static Animator slideOut(Component component, int duration, Animator.StateChangedListener listener,
                                    Direction direction) {
        return slide(component, duration, listener, true, true, direction);
    }

    /**
     * <p>对 Component 做上下位移的退场动画</p>
     * <p>相关方法 {@link #slideIn(Component, int, Animator.StateChangedListener, boolean, Direction)}</p>
     *
     * @param component 做动画的 View
     * @param duration 动画时长(毫秒)
     * @param listener 动画回调
     * @param isNeedAnimation 是否需要动画
     * @param direction 进场动画的方向
     * @param isOut 是否是出来
     * @return 动画对应的 Animator 对象, 注意无动画时返回 null
     */
    public static Animator slide(Component component, int duration, Animator.StateChangedListener listener,
                                 boolean isNeedAnimation, boolean isOut, Direction direction) {
        if (component == null) {
            return null;
        }
        if (isNeedAnimation) {
            AnimatorProperty animatorProperty = new AnimatorProperty(component);
            int width = component.getWidth();
            int height = component.getHeight();
            if (width == 0) {
                width = DisplayUtils.getDisplayWidthInPx(component.getContext());
            }
            if (height == 0) {
                height = DisplayUtils.getDisplayHeightInPx(component.getContext());
            }
            int top = component.getTop();
            switch (direction) {
                case LEFT_TO_RIGHT:
                    if (isOut) {
                        animatorProperty.moveFromX(0).moveToX(width);
                    } else {
                        animatorProperty.moveFromX(-width).moveToX(0);
                    }
                    break;
                case TOP_TO_BOTTOM:
                    animatorProperty.moveFromY(top - height).moveToY(top);
                    break;
                case RIGHT_TO_LEFT:
                    if (isOut) {
                        animatorProperty.moveFromX(0).moveToX(-width);
                    } else {
                        animatorProperty.moveFromX(width).moveToX(0);
                    }
                    break;
                case BOTTOM_TO_TOP: { // 从下往上
                    animatorProperty.moveFromY(top).moveToY(top - height);
                    break;
                }
                default:
                    break;
            }

            animatorProperty.setDuration(duration);
            animatorProperty.setCurveType(Animator.CurveType.DECELERATE);
            animatorProperty.setStateChangedListener(new Animator.StateChangedListener() {
                @Override
                public void onStart(Animator animator) {
                    if (listener != null) {
                        listener.onStart(animator);
                    }
                    component.setVisibility(Component.VISIBLE);
                }

                @Override
                public void onStop(Animator animator) {
                    if (listener != null) {
                        listener.onStop(animator);
                    }
                }

                @Override
                public void onCancel(Animator animator) {
                    if (listener != null) {
                        listener.onCancel(animator);
                    }
                }

                @Override
                public void onEnd(Animator animator) {
                    if (listener != null) {
                        listener.onEnd(animator);
                    }
                    if (isOut) {
                        component.setVisibility(Component.HIDE);
                        animatorProperty.reset();
                    }
                }

                @Override
                public void onPause(Animator animator) {
                    if (listener != null) {
                        listener.onPause(animator);
                    }
                }

                @Override
                public void onResume(Animator animator) {
                    if (listener != null) {
                        listener.onResume(animator);
                    }
                }
            });
            animatorProperty.start();
            return animatorProperty;
        } else {
            component.createAnimatorProperty();
            if (isOut) {
                component.setVisibility(Component.HIDE);
            } else {
                component.setVisibility(Component.VISIBLE);
            }
            return null;
        }
    }

    /**
     * 设置控件的可见度
     *
     * @param component 控件
     * @param isShow 是否可见
     */
    public static void setVisibility(Component component, boolean isShow) {
        if (component != null) {
            component.setVisibility(isShow ? Component.VISIBLE : Component.HIDE);
        }
    }

    /**
     * 设置控件的可见度
     *
     * @param component 控件
     * @param visibility 可见状态
     */
    public static void setVisibility(Component component, int visibility) {
        if (component != null) {
            component.setVisibility(visibility);
        }
    }

    /**
     * 设置控件是否可用
     *
     * @param component 控件
     * @param enabled 是否可用
     */
    public static void setEnabled(Component component, boolean enabled) {
        if (component != null) {
            component.setEnabled(enabled);
            if (component instanceof TextField) {
                component.setFocusable(enabled ? TextField.FOCUS_ENABLE : TextField.FOCUS_DISABLE);
                component.setTouchFocusable(enabled);
            }
        }
    }

    /**
     * 设置控件的文字
     *
     * @param text 控件
     * @param content 文字
     */
    public static void setText(Text text, String content) {
        if (text != null) {
            text.setText(content);
        }
    }

    /**
     * 设置控件的文字
     *
     * @param text 控件
     * @param textId 文字资源
     */
    public static void setText(Text text, int textId) {
        if (text != null) {
            text.setText(textId);
        }
    }

    /**
     * 获取并解析rawfile目录下字体
     *
     * @param context 上下文
     * @param rawFileName 字体文件名路径, 如:resources/rawfile/abc.tft
     * @return 解析的字体
     */
    public static Font createFontBuild(Context context, String rawFileName) {
        ResourceManager resManager = context.getResourceManager();
        RawFileEntry rawFileEntry = resManager.getRawFileEntry(rawFileName);
        Resource resource = null;
        try {
            resource = rawFileEntry.openRawFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
        File file = new File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), rawFileName);
        OutputStream outputStream = null;
        try {
            outputStream = new FileOutputStream(file);
            int index;
            byte[] bytes = new byte[1024];
            while (resource != null && (index = resource.read(bytes)) != -1) {
                outputStream.write(bytes, 0, index);
                outputStream.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            IoUtils.ioClose(resource, outputStream);
        }
        Font.Builder builder = new Font.Builder(file);
        return builder.build();
    }


    /**
     * 设置控件的字体
     *
     * @param view 控件
     * @param font 字体
     */
    public static void setViewTextFont(Component view, Font font) {
        if (view == null || font == null) {
            return;
        }
        if (view instanceof Text) {
            ((Text) view).setFont(font);

        } else if (view instanceof ComponentContainer) {
            ComponentContainer viewGroup = (ComponentContainer) view;
            for (int i = 0; i < viewGroup.getChildCount(); i++) {
                setViewTextFont(viewGroup.getComponentAt(i), font);
            }
        }
    }

    /**
     * 设置控件的字体
     *
     * @param font 字体
     * @param views 控件集合
     */
    public static void setViewsFont(Font font, Component... views) {
        if (font == null || views == null || views.length == 0) {
            return;
        }
        for (Component view : views) {
            setViewTextFont(view, font);
        }
    }

    /**
     * 设置控件的字体
     *
     * @param views 控件集合
     */
    public static void setViewsFont(Component... views) {
        // setViewsFont(XUI.getDefaultTypeface(), views);
    }

    /**
     * 设置控件的文字颜色
     *
     * @param text 控件
     * @param colorId 文字颜色
     */
    public static void textColorId(Text text, int colorId) {
        if (text != null) {
            text.setTextColor(new Color(getColor(text.getContext(), colorId)));
        }
    }

    /**
     * 返回colorId对应的颜色
     *
     * @param context context
     * @param colorId colorId
     * @return return
     */
    public static int getColor(Context context, int colorId) {
        try {
            return context.getResourceManager().getElement(colorId).getColor();
        } catch (IOException | NotExistException | WrongTypeException e) {
            e.printStackTrace();
        }
        return 0;
    }

    /**
     * 设置控件的图片资源
     *
     * @param image 控件
     * @param imageId 图片资源ID
     */
    public static void setImageResource(Image image, int imageId) {
        if (image != null) {
            image.setPixelMap(imageId);
        }
    }

    /**
     * 设置控件的图片资源
     *
     * @param image 控件
     * @param drawable 图片资源
     */
    public static void setImageDrawable(Image image, Element drawable) {
        if (image != null) {
            image.setImageElement(drawable);
        }
    }

    /**
     * 设置控件的图片资源
     *
     * @param image 控件
     * @param element 图片资源
     */
    public static void setImageElement(Image image, Element element) {
        if (image != null) {
            image.setImageElement(element);
        }
    }

    /**
     * 设置控件的图片资源
     *
     * @param image 控件
     * @param uri 图片资源
     */
    public static void setImageUri(Image image, Object uri) {
        if (image != null) {
            ImageLoader.get().loadImage(image, uri);
        }
    }

    /**
     * 设置控件的选中状态
     *
     * @param absButton 控件
     * @param isCheck 是否选中
     */
    public static void setChecked(AbsButton absButton, boolean isCheck) {
        if (absButton != null) {
            absButton.setChecked(isCheck);
        }
    }

    /**
     * 设置控件的选中监听
     *
     * @param absButton 控件
     * @param checkedChangeListener 选中监听
     */
    public static void setOnCheckedChangeListener(AbsButton absButton,
                                                  AbsButton.CheckedStateChangedListener checkedChangeListener) {
        if (absButton != null) {
            absButton.setCheckedStateChangedListener(checkedChangeListener);
        }
    }

    /**
     * 设置控件的选中状态【静默】
     *
     * @param absButton 控件
     * @param isCheck 是否选中
     * @param checkedChangeListener 选中监听
     */
    public static void setCheckedSilent(AbsButton absButton, boolean isCheck,
                                        AbsButton.CheckedStateChangedListener checkedChangeListener) {
        if (absButton != null) {
            absButton.setCheckedStateChangedListener(null);
            absButton.setChecked(isCheck);
            absButton.setCheckedStateChangedListener(checkedChangeListener);
        }
    }

    /**
     * 设置控件的padding
     *
     * @param component 控件
     * @param padding
     */
    public static void setPadding(Component component, int padding) {
        if (component != null) {
            component.setPadding(padding, padding, padding, padding);
        }
    }

    /**
     * 对 Component 设置 paddingLeft
     *
     * @param component 需要被设置的 View
     * @param value 设置的值
     */
    public static void setPaddingLeft(Component component, int value) {
        if (value != component.getPaddingLeft()) {
            component.setPadding(value, component.getPaddingTop(), component.getPaddingRight(), component.getPaddingBottom());
        }
    }

    /**
     * 对 Component 设置 paddingStart
     *
     * @param component 需要被设置的 View
     * @param value 设置的值
     */
    public static void setPaddingStart(Component component, int value) {
        if (value != component.getPaddingStart()) {
            component.setPaddingRelative(value, component.getPaddingTop(), component.getPaddingEnd(), component.getPaddingBottom());
        }
    }

    /**
     * 对 Component 设置 paddingTop
     *
     * @param component 需要被设置的 View
     * @param value 设置的值
     */
    public static void setPaddingTop(Component component, int value) {
        if (value != component.getPaddingTop()) {
            component.setPadding(component.getPaddingLeft(), value, component.getPaddingRight(), component.getPaddingBottom());
        }
    }

    /**
     * 对 Component 设置 paddingRight
     *
     * @param component 需要被设置的 View
     * @param value 设置的值
     */
    public static void setPaddingRight(Component component, int value) {
        if (value != component.getPaddingRight()) {
            component.setPadding(component.getPaddingLeft(), component.getPaddingTop(), value, component.getPaddingBottom());
        }
    }

    /**
     * 对 Component 设置 paddingEnd
     *
     * @param component 需要被设置的 View
     * @param value 设置的值
     */
    public static void setPaddingEnd(Component component, int value) {
        if (value != component.getPaddingEnd()) {
            component.setPaddingRelative(component.getPaddingStart(), component.getPaddingTop(), value, component.getPaddingBottom());
        }
    }

    /**
     * 对 Component 设置 paddingBottom
     *
     * @param component 需要被设置的 View
     * @param value 设置的值
     */
    public static void setPaddingBottom(Component component, int value) {
        if (value != component.getPaddingBottom()) {
            component.setPadding(component.getPaddingLeft(), component.getPaddingTop(), component.getPaddingRight(), value);
        }
    }

    public static void safeSetImageViewSelected(Image imageView, boolean selected) {
        imageView.setSelected(selected);
    }

    /**
     * 判断 ListComponent 是否已经滚动到底部。
     *
     * @param listContainer 需要被判断的 ListView。
     * @return ListComponent 已经滚动到底部则返回 true，否则返回 false。
     */
    public static boolean isListViewAlreadyAtBottom(ListContainer listContainer) {
        if (listContainer.getItemProvider() == null || listContainer.getHeight() == 0) {
            return false;
        }
        if (listContainer.getLastVisibleItemPosition() == listContainer.getItemProvider().getCount() - 1) {
            Component componentAt = listContainer.getComponentAt(listContainer.getChildCount() - 1);
            return componentAt != null && componentAt.getBottom() == listContainer.getHeight();
        }
        return false;
    }

    /**
     * Retrieve the transformed bounding rect of an arbitrary descendant view.
     * This does not need to be a direct child.
     *
     * @param parent parent
     * @param descendant descendant view to reference
     * @param out rect to set to the bounds of the descendant view
     */
    public static void getDescendantRect(ComponentContainer parent, Component descendant, Rect out) {
        out.set(0, 0, descendant.getWidth(), descendant.getHeight());
        ComponentContainerHelper.offsetDescendantRect(parent, descendant, out);
    }

    private static class ComponentContainerHelper {
        private static final ThreadLocal<Matrix> MATRIX_THREAD_LOCAL = new ThreadLocal<>();
        private static final ThreadLocal<RectFloat> RECT_F_THREAD_LOCAL = new ThreadLocal<>();

        public static void offsetDescendantRect(ComponentContainer group, Component child, Rect rect) {
            Matrix m = MATRIX_THREAD_LOCAL.get();
            if (m == null) {
                m = new Matrix();
                MATRIX_THREAD_LOCAL.set(m);
            } else {
                m.reset();
            }

            offsetDescendantMatrix(group, child, m);

            RectFloat rectF = RECT_F_THREAD_LOCAL.get();
            if (rectF == null) {
                rectF = new RectFloat();
                RECT_F_THREAD_LOCAL.set(rectF);
            }
            rectF.modify(rect);
            m.mapRect(rectF);
            rect.set((int) (rectF.left + 0.5f), (int) (rectF.top + 0.5f),
                (int) (rectF.right + 0.5f), (int) (rectF.bottom + 0.5f));
        }

        static void offsetDescendantMatrix(ComponentParent target, Component component, Matrix m) {
            final ComponentParent parent = component.getComponentParent();
            if (parent instanceof Component && parent != target) {
                final Component vp = (Component) parent;
                offsetDescendantMatrix(target, vp, m);
                m.preTranslate(-vp.getScrollValue(Component.AXIS_X), -vp.getScrollValue(Component.AXIS_Y));
            }
            m.preTranslate(component.getLeft(), component.getTop());

            float scaleX = component.getScaleX();
            float scaleY = component.getScaleY();
            if (scaleX != 1F && scaleY != 1F) {
                m.preScale(scaleX, scaleY);
            }
            float rotation = component.getRotation();
            if (rotation != 0F) {
                m.preRotate(rotation);
            }
        }
    }

    /**
     * 方向
     */
    public enum Direction {
        /**
         * 左 -> 右
         */
        LEFT_TO_RIGHT,
        /**
         * 上 -> 下
         */
        TOP_TO_BOTTOM,
        /**
         * 右 -> 左
         */
        RIGHT_TO_LEFT,
        /**
         * 下 -> 上
         */
        BOTTOM_TO_TOP
    }
}
